using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Threading;

using System.Windows.Forms;
using Weazel.Microblaze.Simulator.Engine;
using Weazel.Microblaze.Simulator.Components.Opb;

namespace Weazel.Microblaze.Simulator.Components.Ccd
{
    public class Ccd : OpbSlaveBase
    {
        private uint width;
        private uint height;
        private Bitmap bitmap;
        private int x, y;
        private int index;

        public Ccd(Simulator.Engine.SimulationContext simulator, uint low, uint high)
            : base(simulator)
        {
            this.HighAddress = high;
            this.LowAddress = low;

            x = 0;
            y = 0;
            index = 0;
        }

        public override string GetStatusString()
        {
            return "n/a";
        }

        public override void Run()
        {
            while (true)
                WaitClock();
        }

        public override void Load(byte[] bytes, uint address)
        {
            throw new NotSupportedException();
        }


        public override void BeginTransaction(Transaction transaction)
        {
            uint localAddress = transaction.Address - this.LowAddress;

            if (transaction.Type == Transaction.TransactionType.Read)
            {
                switch (localAddress)
                {
                    case 0:
                        {
                            transaction.Value = width;
                            break;
                        }
                    case 4:
                        {
                            transaction.Value = height;
                            break;
                        }
                    case 8:
                        {
                            // nada
                            break;
                        }
                    case 12:

                        if (bitmap != null)
                        {
                            Color color = bitmap.GetPixel(x, y);
                            transaction.Value = (uint)(color.R + color.G + color.B) / 3;

                            // increment the count
                            if (x + 1 < width)
                            {
                                x++;
                            }
                            else if (y + 1 < height)
                            {
                                x = 0;
                                y++;
                            }
                            else
                            {
                                x = 0;
                                y = 0;
                            }
                        }
                        else
                            transaction.Value = 0;
                        break;

                    default:
                        break;
                }
            }
            else if (transaction.Type == Transaction.TransactionType.Write)
            {

                switch (localAddress)
                {
                    case 0:
                        {
                            this.width = transaction.Value;
                            break;
                        }
                    case 4:
                        {
                            this.height = transaction.Value;
                            break;
                        }
                    case 8:
                        {
                            GetBitmap();
                            // image should be saved to "bitmap" at this time                        
                            break;
                        }
                    case 12:
                        {
                            break;
                        }
                    default:
                        {
                            // nada
                            break;
                        }
                }
            }

            transaction.Status = Transaction.TransactionStatus.Complete;
        }
      
      

        public Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
        {
            Bitmap result = new Bitmap(nWidth, nHeight);
            Graphics g = Graphics.FromImage((Image)result);
            g.DrawImage(b, 0, 0, nWidth, nHeight);             
            return result;
        }

        /// <summary>
        /// Used to notify GetBitmap() that ShowGuiThreadBody() has completed
        /// </summary>
        private AutoResetEvent showGuiDoneEvent;

        /// <summary>
        /// Cannot open a dialog with a MTA thread. Create a new STA thread
        /// to show the dialog.
        /// </summary>
        private void GetBitmap()
        {
            Thread t = new Thread(new ThreadStart(ShowGuiThreadBody));
            showGuiDoneEvent = new AutoResetEvent(false);
            t.SetApartmentState(ApartmentState.STA);
            t.Start();

            // wait for the thread to complete its work
            showGuiDoneEvent.WaitOne();

            // terminate the thread
            t.Abort();
        }

        private void ShowGuiThreadBody()
        {
            OpenFileDialog dialog = new OpenFileDialog();

            // user MUST choose an image
            while (dialog.ShowDialog() != DialogResult.OK)
            {
                if (System.Windows.Forms.MessageBox.Show(
                    "Abort simulation?", "Warning", MessageBoxButtons.YesNo)
                    == DialogResult.Yes)
                    System.Environment.Exit(1);

            }

            Image image = Image.FromFile(dialog.FileName);
            this.bitmap = ResizeBitmap(new Bitmap(image), (int)width, (int)height);

            // work done, notify caller
            showGuiDoneEvent.Set();
        }
    }
}
